///-------------------------------------------------------------------------------------------------
// file:	CoreClasses\Camera\Paths\LagrangeInterpolationMethods.h
//
// summary:	Declares the lagrange interpolation method for path creation
#pragma once

#include "CameraPaths.h"
#include "..\..\Point\Point2D\Point2D.h"
#include "..\..\Point\Point3D\Point3D.h"

#include "Checkpoints/Checkpoints.h"


namespace Engine 
{
	///-------------------------------------------------------------------------------------------------
	/// <summary>	A lagrange interpolation. </summary>
	///
	/// <remarks>	Adrian, 20/08/2015. </remarks>
	///-------------------------------------------------------------------------------------------------
	class LagrangeInterpolation : public CameraPaths
	{

	public:

		LagrangeInterpolation(vector<Checkpoint*> p_pointsToAdd, string p_pathName, float p_deltaMovment)
		{
			//AddPoints(p_pointsToAdd);
			m_deltaMovment = p_deltaMovment;
			m_pathName = p_pathName;
			m_checkPoints = p_pointsToAdd;
			ComputeCrumbles(p_pointsToAdd);
		}

		LagrangeInterpolation(vector<Checkpoint*> p_pointsToAdd)
		{
			ComputeCrumbles(p_pointsToAdd);
		}

		using CameraPaths::GetPoint;
		Point3D GetPoint(float p_x)
		{
			Point2D result = GetInterpolationPointForZ(p_x);
			float yValue = m_pathPoints[0]->m_position.y;
			return Engine::Point3D(result.x, yValue, result.y);
		}

	private:

		using CameraPaths::ComputeCrumbles;
		virtual void ComputeCrumbles(vector<Checkpoint*> p_CheckPoints)
		{
			for (int index = 0; index < p_CheckPoints.size() - 1; index++)
			{
				//m_pathPoints.push_back(p_CheckPoints[index]);

				Checkpoint* currentCheckpoint = p_CheckPoints[index];
				Checkpoint* nextCheckPoint = p_CheckPoints[index + 1];


				if (p_CheckPoints[index + 1]->m_angle > 0 || p_CheckPoints[index+1]->m_angle < 0)
				{
					float rotationDelta = p_CheckPoints[index + 1]->m_angle / 6;
					float totalTurnAmoutn = 0;
					int direction = GetDirection(0, nextCheckPoint->m_angle);

					while (CheckStatus(totalTurnAmoutn, nextCheckPoint->m_angle, direction))
					{
						m_pathPoints.push_back(new Crumble(currentCheckpoint->m_position, rotationDelta));
						totalTurnAmoutn += rotationDelta;
					}
				}

				if (GetChangingAxis(p_CheckPoints[index]->m_position, p_CheckPoints[index + 1]->m_position) == 0)
				{
					float deltaChange = abs(nextCheckPoint->m_position.x - currentCheckpoint->m_position.x) / m_deltaMovment;

					Checkpoint* toAdd = new Checkpoint(currentCheckpoint->m_position, 0);

					int direction = GetDirection(currentCheckpoint->m_position.x, nextCheckPoint->m_position.x);
					m_pathPoints.push_back(new Checkpoint(toAdd));


					while (CheckStatus(toAdd->m_position.x, nextCheckPoint->m_position.x, direction))
					{
						toAdd->m_position.x = direction == 0 ? toAdd->m_position.x + m_deltaMovment : toAdd->m_position.x - m_deltaMovment;
						m_pathPoints.push_back(new Checkpoint(toAdd->m_position, 0));
					}
				}
				else
				{
					//float deltaChange = abs(nextCheckPoint->m_position.z - currentCheckpoint->m_position.z) / m_deltaMovment;

					Checkpoint* toAdd = new Checkpoint(currentCheckpoint->m_position, 0);

					int direction = GetDirection(currentCheckpoint->m_position.z, nextCheckPoint->m_position.z);
					m_pathPoints.push_back(new Checkpoint(toAdd));
					

					while (CheckStatus(toAdd->m_position.z, nextCheckPoint->m_position.z, direction))
					{
						toAdd->m_position.z = direction  == 0? toAdd->m_position.z + m_deltaMovment : toAdd->m_position.z - m_deltaMovment ;
						m_pathPoints.push_back(new Checkpoint(Point3D(toAdd->m_position.x, toAdd->m_position.y, toAdd->m_position.z),0));
					}
				}
			}
		}

		Checkpoint* GetNextPosition()
		{
			int tempIndex = m_currentPositionIndex;
			m_currentPositionIndex++;
			return m_pathPoints[tempIndex];
		}

	};
}